home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / pascal / pibcat.zip / PIBCATS4.PAS < prev    next >
Pascal/Delphi Source File  |  1989-03-31  |  25KB  |  615 lines

  1. (*----------------------------------------------------------------------*)
  2. (*          Move_File_Info --- Save file information for sorting        *)
  3. (*----------------------------------------------------------------------*)
  4.  
  5. PROCEDURE Move_File_Info(     Full : SearchRec;
  6.                           VAR Short: Short_Dir_Record );
  7.  
  8. (*----------------------------------------------------------------------*)
  9. (*                                                                      *)
  10. (*    Procedure: Move_File_Info                                         *)
  11. (*                                                                      *)
  12. (*    Purpose:   Saves information about file in compact form           *)
  13. (*                                                                      *)
  14. (*    Calling sequence:                                                 *)
  15. (*                                                                      *)
  16. (*       Move_File_Info(     Full : SearchRec;                          *)
  17. (*                       VAR Short: Short_Dir_Record );                 *)
  18. (*                                                                      *)
  19. (*          Full  --- Directory info as retrieved from DOS              *)
  20. (*          Short --- Directory info with garbage thrown out            *)
  21. (*                                                                      *)
  22. (*    Remarks:                                                          *)
  23. (*                                                                      *)
  24. (*       This routine copies the useful stuff about a file to a         *)
  25. (*       shorter record which is more easily sorted.                    *)
  26. (*                                                                      *)
  27. (*----------------------------------------------------------------------*)
  28.  
  29. BEGIN (* Move_File_Info *)
  30.  
  31.    Short.File_Time    := Full.Time;
  32.    Short.File_Size    := Full.Size;
  33.    Short.File_Attr    := Full.Attr;
  34.    Short.File_Name    := Full.Name + DUPL( ' ' , 12 - LENGTH( Full.Name ) );
  35.  
  36. END   (* Move_File_Info *);
  37.  
  38. (*----------------------------------------------------------------------*)
  39. (*        Display_File_Info --- Display information about a file        *)
  40. (*----------------------------------------------------------------------*)
  41.  
  42. PROCEDURE Display_File_Info( Dir_Entry : Short_Dir_Record );
  43.  
  44. (*----------------------------------------------------------------------*)
  45. (*                                                                      *)
  46. (*    Procedure: Display_File_Info                                      *)
  47. (*                                                                      *)
  48. (*    Purpose:   Displays information for current file                  *)
  49. (*                                                                      *)
  50. (*    Calling sequence:                                                 *)
  51. (*                                                                      *)
  52. (*       Display_File_Info( Dir_Entry : Short_Dir_Record );             *)
  53. (*                                                                      *)
  54. (*          Dir_Entry --- Directory record describing file              *)
  55. (*                                                                      *)
  56. (*    Remarks:                                                          *)
  57. (*                                                                      *)
  58. (*       The counters for total number of files and total file space    *)
  59. (*       used are incremented here.                                     *)
  60. (*                                                                      *)
  61. (*----------------------------------------------------------------------*)
  62.  
  63. CONST
  64.    Null_Path_Name : AnyStr = '';
  65.  
  66. VAR
  67.    STime   : STRING[10];
  68.    SDate   : STRING[10];
  69.    I       : INTEGER;
  70.  
  71. BEGIN (* Display_File_Info *)
  72.  
  73.                                    (* Handle condensed listing *)
  74.    IF Do_Condensed_Listing THEN
  75.       Write_Condensed_Line( Dir_Entry.File_Name, Dir_Entry.File_Size,
  76.                             Dir_Entry.File_Time, Null_Path_Name,
  77.                             Current_Subdirectory )
  78.  
  79.    ELSE                            (* Handle normal listing *)
  80.       WITH Dir_Entry DO
  81.          BEGIN
  82.                                    (* Get date and time of creation *)
  83.  
  84.             Dir_Convert_Date_And_Time( File_Time , SDate , STime );
  85.  
  86.                                    (* Ensure space left this page *)
  87.  
  88.             IF ( Lines_Left < 1 ) THEN
  89.                Display_Page_Titles;
  90.  
  91.                                    (* Write out file name *)
  92.  
  93.             WRITE( Output_File , Left_Margin_String , '      ' , File_Name );
  94.  
  95.             FOR I := LENGTH( File_Name ) TO 14 DO
  96.                WRITE( Output_File , ' ' );
  97.  
  98.                                    (* Write length, date, and time *)
  99.  
  100.             WRITE  ( Output_File , File_Size:8 , '  ' );
  101.             WRITE  ( Output_File , SDate  , '  ' );
  102.             WRITE  ( Output_File , STime );
  103.             WRITELN( Output_File );
  104.  
  105.                                    (* Update count of lines left   *)
  106.  
  107.             IF Do_Printer_Format THEN
  108.                DEC( Lines_Left );
  109.  
  110.          END;
  111.                                    (* Increment total file count   *)
  112.    INC( Total_Files );
  113.  
  114.                                    (* Increment total space used   *)
  115.  
  116.    Total_Space := Total_Space + Dir_Entry.File_Size;
  117.  
  118. END   (* Display_File_Info *);
  119.  
  120. (*----------------------------------------------------------------------*)
  121. (*          Sort_Files --- Sort files in ascending order by name        *)
  122. (*----------------------------------------------------------------------*)
  123.  
  124. PROCEDURE Sort_Files( First : INTEGER;
  125.                       Last  : INTEGER );
  126.  
  127. (*----------------------------------------------------------------------*)
  128. (*                                                                      *)
  129. (*    Procedure: Sort_Files                                             *)
  130. (*                                                                      *)
  131. (*    Purpose:   Sorts file names in current directory                  *)
  132. (*                                                                      *)
  133. (*    Calling sequence:                                                 *)
  134. (*                                                                      *)
  135. (*       Sort_Files( First : INTEGER; Last : INTEGER );                 *)
  136. (*                                                                      *)
  137. (*          First --- First entry in 'File_Stack' to sort               *)
  138. (*          Last  --- Last entry in 'File_Stack' to sort                *)
  139. (*                                                                      *)
  140. (*    Remarks:                                                          *)
  141. (*                                                                      *)
  142. (*       A shell sort is used to put the file names for the current     *)
  143. (*       directory in ascending order.  The current directory's files   *)
  144. (*       are bracketed by 'First' and 'Last'.                           *)
  145. (*                                                                      *)
  146. (*----------------------------------------------------------------------*)
  147.  
  148. VAR
  149.    Temp : Short_Dir_Record;
  150.    I    : INTEGER;
  151.    J    : INTEGER;
  152.    D    : INTEGER;
  153.  
  154. BEGIN (* Sort_Files *)
  155.  
  156.    D := SUCC( Last - First );
  157.  
  158.    WHILE( D > 1 ) DO
  159.       BEGIN
  160.  
  161.          IF ( D < 5 ) THEN
  162.             D := 1
  163.          ELSE
  164.             D := TRUNC( 0.45454 * D );
  165.  
  166.          FOR I := ( Last - D ) DOWNTO First DO
  167.             BEGIN
  168.  
  169.                Temp       := File_Stack[ I SHR SegShift ]^[ I AND MaxFiles ];
  170.                J          := I + D;
  171.  
  172.                WHILE( ( Temp.File_Name >
  173.                         File_Stack[ J SHR SegShift ]^[ J AND MaxFiles ].File_Name ) AND
  174.                       ( J <= Last ) ) DO
  175.                   BEGIN
  176.                      File_Stack[ ( J - D ) SHR SegShift ]^[ ( J - D ) AND MaxFiles ] :=
  177.                         File_Stack[ J SHR SegShift ]^[ J AND MaxFiles ];
  178.                      J               := J + D;
  179.                   END;
  180.  
  181.                File_Stack[ ( J - D ) SHR SegShift ]^[ ( J - D ) AND MaxFiles ] := Temp;
  182.  
  183.             END;
  184.  
  185.       END;
  186.  
  187. END   (* Sort_Files *);
  188.  
  189. (*----------------------------------------------------------------------*)
  190. (*          Find_Files --- Recursively search directories for files     *)
  191. (*----------------------------------------------------------------------*)
  192.  
  193. PROCEDURE Find_Files( VAR Subdir    : AnyStr;
  194.                       VAR File_Spec : AnyStr;
  195.                           Attr      : INTEGER;
  196.                           Levels    : INTEGER );
  197.  
  198. (*----------------------------------------------------------------------*)
  199. (*                                                                      *)
  200. (*    Procedure: Find_Files                                             *)
  201. (*                                                                      *)
  202. (*    Purpose:   Recursively traverses directories looking for files    *)
  203. (*                                                                      *)
  204. (*    Calling sequence:                                                 *)
  205. (*                                                                      *)
  206. (*       Find_Files( VAR Subdir    : AnyStr;                            *)
  207. (*                   VAR File_Spec : AnyStr;                            *)
  208. (*                       Attr      : INTEGER;                           *)
  209. (*                       Levels    : INTEGER );                         *)
  210. (*                                                                      *)
  211. (*          Subdir    --- subdirectory name of this level               *)
  212. (*          File_Spec --- DOS file spec to match                        *)
  213. (*          Attr      --- attribute type to match                       *)
  214. (*          Levels    --- current subdirectory level depth              *)
  215. (*                                                                      *)
  216. (*    Remarks:                                                          *)
  217. (*                                                                      *)
  218. (*       This is the actual heart of PibCat.  This routine invokes      *)
  219. (*       itself recursively to traverse all subdirectories looking for  *)
  220. (*       files which match the given file specification.                *)
  221. (*                                                                      *)
  222. (*----------------------------------------------------------------------*)
  223.  
  224. VAR
  225.    Dir_Entry  : SearchRec;
  226.    Path       : AnyStr;
  227.    Error      : INTEGER;
  228.    I          : INTEGER;
  229.    Dir        : STRING[14];
  230.    Cur_Count  : INTEGER;
  231.    Skip_Attr  : INTEGER;
  232.    Files_Here : INTEGER;
  233.    ISeg       : INTEGER;
  234.    IOff       : INTEGER;
  235.    FileName   : AnyStr;
  236.  
  237. LABEL  Quit;
  238.  
  239. BEGIN  (* Find_Files *)
  240.                                    (* Save current file count *)
  241.    Cur_Count  := File_Count;
  242.                                    (* No files in this directory yet *)
  243.    Files_Here := 0;
  244.                                    (* Don't list directories as files *)
  245.  
  246.    Skip_Attr := VolumeID + Directory;
  247.  
  248.    IF ( Levels >= 1 ) THEN
  249.       BEGIN
  250.                                    (* Get full file spec to search for *)
  251.  
  252.          Path := Subdir + File_Spec;
  253.  
  254.                                    (* Get first file on this level *)
  255.  
  256.          FindFirst( Path, AnyFile, Dir_Entry );
  257.          Error := DosError;
  258.  
  259.                                    (* Get info on remaining files  *)
  260.                                    (* on this level.               *)
  261.          WHILE ( Error = 0 ) DO
  262.             BEGIN
  263.                                    (* Increment count of files in this dir *)
  264.                                    (* including subdirectories             *)
  265.  
  266.                INC( File_Count );
  267.  
  268.                                    (* Increment non-directory file count *)
  269.  
  270.                IF ( ( Dir_Entry.Attr AND Skip_Attr ) = 0 ) THEN
  271.                    INC( Files_Here );
  272.  
  273.                                    (* Save info on this file *)
  274.  
  275.                Move_File_Info ( Dir_Entry ,
  276.                                 File_Stack[ File_Count SHR SegShift ]^[ File_Count AND MaxFiles ] );
  277.  
  278.                                    (* Get next file entry *)
  279.  
  280.                FindNext( Dir_Entry );
  281.                Error := DosError;
  282.  
  283.                                    (* Check for ^C at keyboard *)
  284.                IF KeyPressed THEN
  285.                   IF QuitFound THEN
  286.                      GOTO Quit;
  287.  
  288.             END;
  289.                                    (* Sort file names              *)
  290.  
  291.          Sort_Files( SUCC( Cur_Count ) , File_Count );
  292.  
  293.                                    (* Increment directory count    *)
  294.          INC ( Total_Dirs );
  295.  
  296.                                    (* Report scanning this subdirectory *)
  297.  
  298.          WRITELN( Status_File , ' Scanning: ', Subdir );
  299.  
  300.                                    (* Display file info header *)
  301.  
  302.          IF ( Files_Here > 0 ) THEN
  303.             BEGIN
  304.  
  305.                Subdir_Title := Left_Margin_String + ' Directory: ' + Subdir;
  306.  
  307.                IF ( NOT Do_Condensed_Listing ) THEN
  308.                   IF Do_Printer_Format THEN
  309.                      IF ( Lines_Left < 4 ) THEN
  310.                         Display_Page_Titles
  311.                      ELSE
  312.                         BEGIN
  313.                            WRITELN( Output_File );
  314.                            WRITELN( Output_File , Subdir_Title );
  315.                            WRITELN( Output_File );
  316.                         END
  317.                   ELSE
  318.                      BEGIN
  319.                         WRITELN( Output_File );
  320.                         WRITELN( Output_File , Subdir_Title );
  321.                         WRITELN( Output_File );
  322.                      END;
  323.                                    (* Count lines left on page *)
  324.  
  325.                IF Do_Printer_Format THEN
  326.                   BEGIN
  327.                      DEC( Lines_Left , 3 );
  328.                      IF ( Lines_Left < 1 ) THEN
  329.                         Display_Page_Titles;
  330.                   END;
  331.  
  332.             END;
  333.                                    (* Remove drive from path for      *)
  334.                                    (* display purposes.               *)
  335.  
  336.          Current_Subdirectory := Subdir;
  337.  
  338.          I      := POS( ':' , Current_Subdirectory );
  339.  
  340.          IF ( I > 0 ) THEN
  341.             DELETE( Current_Subdirectory, 1, I );
  342.  
  343.                                    (* Display info on all files       *)
  344.                                    (* But don't display directories!  *)
  345.  
  346.          FOR I := SUCC( Cur_Count ) TO File_Count DO
  347.              BEGIN
  348.  
  349.                 ISeg := I SHR SegShift;
  350.                 IOff := I AND MaxFiles;
  351.  
  352.                                    (* Display info for current file *)
  353.  
  354.                 IF ( ( File_Stack[ ISeg ]^[ IOff ].File_Attr AND Skip_Attr ) = 0 ) THEN
  355.                    Display_File_Info( File_Stack[ ISeg ]^[ IOff ] );
  356.  
  357.                                    (* If we're expanding library files, *)
  358.                                    (* and we're expanding them right    *)
  359.                                    (* after each library name, then     *)
  360.                                    (* check if current file is a lib    *)
  361.                                    (* and expand it.                    *)
  362.  
  363.                 IF ( Expand_Libs AND Expand_Libs_In ) THEN
  364.                    BEGIN
  365.  
  366.                       FileName := File_Stack[ ISeg ]^[ IOff ].File_Name;
  367.  
  368.                       IF      ( POS( '.ARC', FileName ) > 0 ) THEN
  369.                          Display_Archive_Contents( FileName )
  370.                       ELSE IF ( POS( '.ZIP', FileName ) > 0 ) THEN
  371.                          Display_ZIP_Contents( FileName )
  372.                       ELSE IF ( POS( '.LZH', FileName ) > 0 ) THEN
  373.                          Display_LZH_Contents( FileName )
  374.                       ELSE IF ( POS( '.PAK', FileName ) > 0 ) THEN
  375.                          Display_Archive_Contents( FileName )
  376.                       ELSE IF ( POS( '.DWC', FileName ) > 0 ) THEN
  377.                          Display_DWC_Contents( FileName )
  378.                       ELSE IF ( POS( '.LBR', FileName ) > 0 ) THEN
  379.                          Display_Lbr_Contents( FileName )
  380.                       ELSE IF ( POS( '.LZS', FileName ) > 0 ) THEN
  381.                          Display_LZH_Contents( FileName )
  382.                       ELSE IF ( POS( '.MD ', FileName ) > 0 ) THEN
  383.                          Display_MD_Contents( FileName )
  384.                       ELSE IF ( POS( '.ZOO', FileName ) > 0 ) THEN
  385.                          Display_ZOO_Contents( FileName );
  386.  
  387.                    END;
  388.  
  389.                 IF KeyPressed THEN
  390.                    IF QuitFound THEN
  391.                       GOTO Quit;
  392.  
  393.              END;
  394.                                    (* List library file contents if requested *)
  395.  
  396.          IF ( Expand_Libs AND ( NOT Expand_Libs_In ) ) THEN
  397.             BEGIN
  398.                                    (* List contents of any library files *)
  399.  
  400.                FOR I := SUCC( Cur_Count ) TO File_Count DO
  401.                   BEGIN
  402.  
  403.                      ISeg := I SHR SegShift;
  404.                      IOff := I AND MaxFiles;
  405.  
  406.                                    (* If current file is any type of   *)
  407.                                    (* library file, then list contents *)
  408.  
  409.                       FileName := File_Stack[ ISeg ]^[ IOff ].File_Name;
  410.  
  411.                       IF      ( POS( '.ARC', FileName ) > 0 ) THEN
  412.                          Display_Archive_Contents( FileName )
  413.                       ELSE IF ( POS( '.ZIP', FileName ) > 0 ) THEN
  414.                          Display_ZIP_Contents( FileName )
  415.                       ELSE IF ( POS( '.LZH', FileName ) > 0 ) THEN
  416.                          Display_LZH_Contents( FileName )
  417.                       ELSE IF ( POS( '.PAK', FileName ) > 0 ) THEN
  418.                          Display_Archive_Contents( FileName )
  419.                       ELSE IF ( POS( '.DWC', FileName ) > 0 ) THEN
  420.                          Display_DWC_Contents( FileName )
  421.                       ELSE IF ( POS( '.LBR', FileName ) > 0 ) THEN
  422.                          Display_Lbr_Contents( FileName )
  423.                       ELSE IF ( POS( '.LZS', FileName ) > 0 ) THEN
  424.                          Display_LZH_Contents( FileName )
  425.                       ELSE IF ( POS( '.MD ', FileName ) > 0 ) THEN
  426.                          Display_MD_Contents( FileName )
  427.                       ELSE IF ( POS( '.ZOO', FileName ) > 0 ) THEN
  428.                          Display_ZOO_Contents( FileName );
  429.  
  430.                                    (* If <CTRL>Break hit, quit. *)
  431.  
  432.                      IF KeyPressed THEN
  433.                         IF QuitFound THEN
  434.                            GOTO Quit;
  435.  
  436.                   END;
  437.  
  438.             END;
  439.  
  440.          IF ( Levels >= 2 ) THEN
  441.             BEGIN
  442.                                    (* List all subdirectories to given level *)
  443.                                    (* Note: we read through whole directory  *)
  444.                                    (*       again since we probably excluded *)
  445.                                    (*       directories on first pass.       *)
  446.  
  447.                Path := Subdir + '*.*';
  448.  
  449.                                    (* Get first file *)
  450.  
  451.                FindFirst( Path, AnyFile, Dir_Entry );
  452.                Error := DosError;
  453.  
  454.                                    (* While there are files left ... *)
  455.  
  456.                WHILE ( Error = 0 ) DO
  457.                   BEGIN
  458.                                    (* See if it's a subdirectory *)
  459.  
  460.                      IF ( ( Dir_Entry.Attr AND Directory ) <> 0 ) THEN
  461.                         BEGIN
  462.                                    (* Yes -- get subdirectory name *)
  463.  
  464.                            Dir := Dir_Entry.Name;
  465.  
  466.                                    (* Ignore '.' and '..' *)
  467.  
  468.                            IF ( ( Dir <> '.' ) AND ( Dir <> '..') ) THEN
  469.                               BEGIN
  470.  
  471.                                    (* Construct path name for subdirectory *)
  472.  
  473.                                  Path := Subdir + Dir + '\';
  474.  
  475.                                    (* List files in subdirectory *)
  476.  
  477.                                  Find_Files( Path, File_Spec, Attr, PRED( Levels ) );
  478.  
  479.                                  IF User_Break THEN
  480.                                     GOTO Quit;
  481.  
  482.                               END;
  483.  
  484.                         END;
  485.                                    (* Get next file entry *)
  486.  
  487.                      FindNext( Dir_Entry );
  488.                      Error := DosError;
  489.  
  490.                   END (* WHILE *);
  491.  
  492.             END (* IF Levels >= 2 *);
  493.  
  494.       END (* IF Levels >= 1 *);
  495.                                    (* Restore previous file count *)
  496. Quit:
  497.    File_Count := Cur_Count;
  498.  
  499. END   (* Find_Files *);
  500.  
  501. (*----------------------------------------------------------------------*)
  502. (*             Perform_Cataloguing --- Do cataloguing of files          *)
  503. (*----------------------------------------------------------------------*)
  504.  
  505. PROCEDURE Perform_Cataloguing;
  506.  
  507. VAR
  508.    Name      : AnyStr;
  509.    Subdir    : AnyStr;
  510.    File_Spec : AnyStr;
  511.    I         : INTEGER;
  512.    Done      : BOOLEAN;
  513.  
  514. BEGIN (* Perform_Cataloguing *)
  515.                                    (* Display volume label       *)
  516.    Display_Volume_Label;
  517.                                    (* Append disk letter to file spec *)
  518.  
  519.    IF ( POS( '\' , Find_Spec ) = 0 ) THEN
  520.       Name := Cat_Drive + ':\' + Find_Spec
  521.    ELSE
  522.       Name := Cat_Drive + ':' + Find_Spec;
  523.  
  524.                                    (* Make sure some files get looked at! *)
  525.  
  526.    IF Name[ LENGTH( Name ) ] = '\' THEN
  527.       Name := Name + '*.*';
  528.  
  529.                                    (* Split out directory from file spec *)
  530.    Subdir := Name;
  531.    I      := SUCC( LENGTH( Subdir ) );
  532.    Done   := FALSE;
  533.  
  534.    REPEAT
  535.       DEC( I );
  536.       IF ( I > 0 ) THEN
  537.          Done := ( Subdir[ I ] = '\' )
  538.       ELSE
  539.          Done := TRUE;
  540.    UNTIL Done;
  541.  
  542.    I := LENGTH( Subdir ) - I;
  543.  
  544.    File_Spec[ 0 ] := CHR( I );
  545.  
  546.    MOVE( Subdir[ 1 + LENGTH( Subdir ) - I ] , File_Spec[ 1 ] , I );
  547.  
  548.    Subdir[ 0 ] := CHR( LENGTH( Subdir ) - I );
  549.  
  550.                                    (* Begin listing files at specified *)
  551.                                    (* subdirectory                     *)
  552.  
  553.    Find_Files( Subdir, File_Spec, $FF, 9999 );
  554.  
  555. END   (* Perform_Cataloguing *);
  556.  
  557. (*----------------------------------------------------------------------*)
  558. (*                Terminate --- Terminate cataloguing                   *)
  559. (*----------------------------------------------------------------------*)
  560.  
  561. PROCEDURE Terminate;
  562.  
  563. BEGIN (* Terminate *)
  564.                                    (* Note if catalogue terminated by ^C *)
  565.    IF ( NOT Help_Only ) THEN
  566.       IF User_Break THEN
  567.          BEGIN
  568.             IF ( NOT Do_Condensed_Listing ) THEN
  569.                BEGIN
  570.                   IF ( Lines_Left < 6 ) THEN
  571.                      Display_Page_Titles;
  572.                   WRITELN( Output_File );
  573.                   WRITELN( Output_File , Left_Margin_String,
  574.                            '>>>>> ^C typed, catalog listing INCOMPLETE.');
  575.                   WRITELN( Output_File );
  576.                END;
  577.             WRITELN( Status_File , '^C typed, catalog listing INCOMPLETE.' );
  578.          END
  579.       ELSE
  580.          IF ( NOT Do_Condensed_Listing ) THEN
  581.             BEGIN                  (* Indicate file totals *)
  582.  
  583.                IF ( Lines_Left < 9 ) THEN
  584.                   Display_Page_Titles;
  585.  
  586.                WRITELN( Output_File );
  587.                WRITELN( Output_File , Left_Margin_String, ' Totals:');
  588.                WRITELN( Output_File , Left_Margin_String,
  589.                         '    Directories scanned: ',Total_Dirs:10);
  590.                WRITELN( Output_File , Left_Margin_String,
  591.                         '    Files selected     : ',Total_Files:10);
  592.                WRITELN( Output_File , Left_Margin_String,
  593.                         '    Bytes in files     : ',Total_Space:10);
  594.                WRITELN( Output_File , Left_Margin_String,
  595.                         '    Entries selected   : ',Total_Entries:10);
  596.                WRITELN( Output_File , Left_Margin_String,
  597.                         '    Bytes in entries   : ',Total_ESpace:10);
  598.                WRITELN( Output_File , Left_Margin_String,
  599.                         '    Bytes free         : ',
  600.                         DiskFree( SUCC( ORD( Cat_Drive ) - ORD('A') ) ):10 );
  601.             END;
  602.                                    (* Close output file *)
  603.       (*$I-*)
  604.    CLOSE( Output_File );
  605.       (*$I+*)
  606.    IF ( IOResult <> 0 ) THEN;
  607.  
  608.                                    (* Close status file *)
  609.       (*$I-*)
  610.    CLOSE( Status_File );
  611.       (*$I+*)
  612.    IF ( IOResult <> 0 ) THEN;
  613.  
  614. END   (* Terminate *);
  615.